package drds.common.db.xml_mapping.binding;


import drds.common.ClassSearcher;
import drds.common.db.xml_mapping.session.Configuration;
import drds.common.db.xml_mapping.session.MapperContext;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class MapperRegistry {

  private final Configuration configuration;
  private final Map<Class<?>, MapperProxyFactory<?>> classMapperProxyFactoryHashMap = new HashMap<>();

  public MapperRegistry(Configuration configuration) {
    this.configuration = configuration;
  }

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, MapperContext mapperContext) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) classMapperProxyFactoryHashMap.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(mapperContext);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

  public <T> boolean hasMapper(Class<T> type) {
    return classMapperProxyFactoryHashMap.containsKey(type);
  }

  public void addMappers(String packageName) {
    addMappers(packageName, Object.class);
  }

  public void addMappers(String packageName, Class<?> superType) {
    List<Class> mapperSet = ClassSearcher.findSubClass(MapperRegistry.class, superType, packageName);
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }

  public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        classMapperProxyFactoryHashMap.put(type, new MapperProxyFactory<>(type));
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          classMapperProxyFactoryHashMap.remove(type);
        }
      }
    } else {

    }
  }


}
